﻿using System;
using System.Xml;

namespace IntraVision.Xml
{
    public static class XmlUtils
    {
        public static Object IsNull(params Object[] objects)
        {
            foreach (Object o in objects)
            {
                if (o != null) return o;
            }
            return null;
        }
        
        /// <summary>
        /// Добавляет атрибут к узлу
        /// </summary>
        /// <param name="node">узел, к которому нужно добавить атрибут</param>
        /// <param name="attributeName">имя атрибута</param>
        /// <param name="attributeValue">значение атрибута</param>
        public static void AppendAttribute(this XmlNode node, String attributeName, Object attributeValue)
        {
            if (node == null || attributeName == null || attributeName.Length == 0) return;

            XmlAttribute attribute = node.OwnerDocument.CreateAttribute(attributeName);
            attribute.Value = Convert.ToString(attributeValue);
            node.Attributes.Append(attribute);
        }
        public static void AppendAttribute(this XmlNode node, String attributeName)
        {
            AppendAttribute(node, attributeName, null);
        }

        /// <summary>
        /// Добавляет дочерний элемент к узлу
        /// </summary>
        /// <param name="node">узел, к которому нужно добавить элемент</param>
        /// <param name="elementName">имя элемента</param>
        /// <param name="elementText">значение элемента</param>
        /// <returns>Дочерний элемент</returns>
        public static XmlElement AppendElement(this XmlNode node, String elementName, object elementText)
        {
            if (node == null || elementName == null || elementName.Length == 0) return null;

            XmlElement child = null;
            try
            {
                child = (node is XmlDocument) ? ((node as XmlDocument).CreateElement(elementName)) : (node.OwnerDocument.CreateElement(elementName));
                string str = Convert.ToString(elementText);
                if (!string.IsNullOrEmpty(str)) child.InnerXml = str;
                node.AppendChild(child);
            }
            catch { }
            return child;
        }
        public static XmlElement AppendElement(this XmlNode node, String elementName)
        {
            return AppendElement(node, elementName, null);
        }

        /// <summary>
        /// Добавляет дочерний элемент к узлу
        /// </summary>
        /// <param name="node">узел, к которому нужно добавить элемент</param>
        /// <param name="elementName">имя элемента</param>
        /// <param name="elementText">значение элемента</param>
        /// <returns>Дочерний элемент</returns>
        public static XmlElement AppendCDataElement(this XmlNode node, String elementName, object elementText)
        {
            if (node == null || elementName == null || elementName.Length == 0) return null;

            XmlElement child = null;
            try
            {
                child = (node is XmlDocument) ? ((node as XmlDocument).CreateElement(elementName)) : (node.OwnerDocument.CreateElement(elementName));
                string str = Convert.ToString(elementText);
                XmlCDataSection cdata = (node is XmlDocument) ? ((node as XmlDocument).CreateCDataSection(str)) : (node.OwnerDocument.CreateCDataSection(str));
                child.AppendChild(cdata);
                node.AppendChild(child);
            }
            catch { }
            return child;
        }
        public static XmlElement AppendCDataElement(this XmlNode node, String elementName)
        {
            return AppendElement(node, elementName, null);
        }
        /// <summary>
        /// Возвращает значение атрибута или defaultValue, если атрибут не задан.
        /// </summary>
        /// <param name="node">Узел, атрибут которого проверять</param>
        /// <param name="attributeName">Название атрибута</param>
        /// <param name="defaultValue">Значение по умолчанию</param>
        /// <returns>значение атрибута</returns>
        public static String AttributeValue(this XmlNode node, String attributeName, String defaultValue)
        {
            if (node == null || attributeName == null || node.Attributes[attributeName] == null) return defaultValue;
            return XmlUtils.IsNull(node.Attributes[attributeName].Value, defaultValue, null) as String;
        }
        public static String AttributeValue(this XmlNode node, String attributeName)
        {
            return AttributeValue(node, attributeName, "");
        }

        /// <summary>
        /// Возвращает значение узла или defaultValue, если узел не задан
        /// </summary>
        /// <param name="node">Узел, дочерний узел которого надо проверять</param>
        /// <param name="nodeName">Имя дочернего узла</param>
        /// <param name="defaultValue">Значение узла по умолчанию</param>
        /// <returns>значение узла</returns>
        public static String NodeValue(this XmlNode node, String nodeName, String defaultValue)
        {
            if (node == null || nodeName == null || node.SelectSingleNode(nodeName) == null) return defaultValue;
            String result = (node.SelectSingleNode(nodeName).InnerXml.Length > node.SelectSingleNode(nodeName).InnerText.Length) ? node.SelectSingleNode(nodeName).InnerXml : node.SelectSingleNode(nodeName).InnerText;
            return (String)IsNull(result, defaultValue);
        }

        public static String NodeValue(this XmlNode node, String nodeName)
        {
            return NodeValue(node, nodeName, "");
        }
    }

    public class XmlNoNamespaceWriter : System.Xml.XmlTextWriter
    {
        bool skipAttribute = false;

        public XmlNoNamespaceWriter(System.IO.TextWriter writer)
            : base(writer)
        {
        }

        public XmlNoNamespaceWriter(System.IO.Stream stream, System.Text.Encoding encoding)
            : base(stream, encoding)
        {
        }

        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            base.WriteStartElement(null, localName, null);
        }


        public override void WriteStartAttribute(string prefix, string localName, string ns)
        {
            //If the prefix or localname are "xmlns", don't write it.
            if (prefix.CompareTo("xmlns") == 0 || localName.CompareTo("xmlns") == 0)
            {
                skipAttribute = true;
            }
            else
            {
                base.WriteStartAttribute(null, localName, null);
            }
        }

        public override void WriteString(string text)
        {
            //If we are writing an attribute, the text for the xmlns
            //or xmlns:prefix declaration would occur here.  Skip
            //it if this is the case.
            if (!skipAttribute)
            {
                base.WriteString(text);
            }
        }

        public override void WriteEndAttribute()
        {
            //If we skipped the WriteStartAttribute call, we have to
            //skip the WriteEndAttribute call as well or else the XmlWriter
            //will have an invalid state.
            if (!skipAttribute)
            {
                base.WriteEndAttribute();
            }
            //reset the boolean for the next attribute.
            skipAttribute = false;
        }


        public override void WriteQualifiedName(string localName, string ns)
        {
            //Always write the qualified name using only the
            //localname.
            base.WriteQualifiedName(localName, null);
        }
    }
}